import SockJS from 'sockjs-client';
import Stomp from 'stompjs';
import { EventEmitter } from 'events';
import { message } from 'antd';

class VVChat {
    // 链接的客户端
    _client;

    _isConnected;

    // 已订阅的消息
    _subscribed;

    _user;

    _setIntervalId;

    _retrying;

    _sessionId;

    constructor() {
        this._subscribed = new Map();
    }

    // 链接成功callback
    _connectCallback() {
        if (this._setIntervalId) {
            clearInterval(this._setIntervalId);
        }

        this._isConnected = true;
        console.log('%cConnected', 'color: #87d068;');
        this._subscribed.forEach((subs, type) => {
            this._client.subscribe(
                `jms.topic.${this._user}.${type}`,
                msg => {
                    if (Array.isArray(subs)) {
                        subs.map(callback => {
                            if (typeof callback === 'function') {
                                callback({ msg, type });
                            }
                        });
                    }
                },
                { ask: 'client-individual' }
            );
        });
    }

    _retry() {
        console.log('Connection failed, trying again');
        let retrying = false;
        if (this._setIntervalId) {
            clearInterval(this._setIntervalId);
        }
        this._setIntervalId = setInterval(() => {
            if (!retrying) {
                console.log('<<< RETRYING');
                retrying = true;
                this.connection(this._user, this._sessionId);
            }
        }, 5000);
    }

    // 链接失败callback
    _errorCallback() {
        console.log('Connection failed!');
        this._isConnected = false;

        this._retry();
    }

    // 链接socket
    connection(user, sessionId) {
        if (this._client && this._isConnected) {
            return;
        }

        this._user = user;
        this._sessionId = sessionId;
        try {
            const url = `/api/ws/public/pusher?userCode=${this._user}&sessionId=${this._sessionId}`;
            const socket = new SockJS(url, null, { timeout: 15000 });
            this._client = Stomp.over(socket);
            this._client.debug = () => {}; //关闭debug
            this._client.connect(
                {
                    Connection: 'Upgrade',
                    Upgrade: 'websocket'
                },
                this._connectCallback.bind(this),
                this._errorCallback.bind(this)
            );
        } catch (e) {
            this._errorCallback();
        }
    }

    // 断开链接
    disconnect() {
        if (this._setIntervalId) {
            clearInterval(this._setIntervalId);
        }

        if (this._client && this._isConnected) {
            this._client.disconnect(() => {
                this._isConnected = false;
                this._client = null;
                console.log('%cConnection closed!', 'color: #87d068;');
            });
        }
    }

    _addSubscribeToMap(subType, eventCallback) {
        if (Array.isArray(subType)) {
            subType.map(s => {
                if (this._subscribed.has(s)) {
                    const subCallbacks = this._subscribed.get(s);
                    this._subscribed.set(s, [...subCallbacks, eventCallback]);
                } else {
                    this._subscribed.set(s, [eventCallback]);
                }
            });
        } else {
            this._subscribed.set(subType, [eventCallback]);
        }
    }

    /**
     * 消息订阅
     * 如果已经连接则直接订阅，如果尚未连接则存入Map中等待链接成功后订阅消息
     */
    subscribe(subType, eventCallback) {
        if (this._client && this._isConnected) {
            if (Array.isArray(subType)) {
                subType.forEach(s => {
                    this._client.subscribe(`jms.topic.${this._user}.${s}`, msg => eventCallback({ msg, type: s }), {
                        ask: 'client-individual'
                    });
                });
            } else {
                this._client.subscribe(
                    `jms.topic.${this._user}.${subType}`,
                    msg => eventCallback({ msg, type: subType }),
                    {
                        ask: 'client-individual'
                    }
                );
            }
        }
        this._addSubscribeToMap(subType, eventCallback);
    }
}

export default new VVChat();
